package com.kauto.gps;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.kauto.gps.bean.Gps;
import com.kauto.gps.cache.DataCache;
import com.kauto.gps.cache.ICache;
import com.kauto.gps.config.GpsFilesProperties;
import com.kauto.gps.config.GpsFtpProperties;
import com.kauto.gps.util.DateTimeUtil;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class GpsFileManager {
    @Autowired
    private GpsFtpManager gpsFtpManager;
    private ICache<Gps> gpsCache;

    public void init() {
        gpsCache = new DataCache<>("gpsCache", GpsFilesProperties.maxCacheSize);
        log.info("GpsFilesProperties,dir:{},bakDir:{},rootDir:{},maxCacheSize:{}", GpsFilesProperties.dir, GpsFilesProperties.bakDir, GpsFtpProperties.rootDir, GpsFilesProperties.maxCacheSize);
        File dir = new File(GpsFilesProperties.dir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        File bakDir = new File(GpsFilesProperties.bakDir);
        if (!bakDir.exists()) {
            bakDir.mkdirs();
        }

        new GpsFileWriter().start();
        log.info("GpsFileWriter started...");
        new CLearGpsFile().start();
        log.info("CLearGpsFile started...");
    }

    public boolean addGpsList(List<Gps> list) {
        if (list != null && list.size() > 0) {
            return gpsCache.addDataList(list);
        }
        return false;
    }

    class GpsFileWriter extends Thread {
        private int writeTotal = 0;
        private BufferedWriter bufferedWriter;
        private FileWriter fileWriter;
        private File gpsFile;
        private long start;
        private long end;

        public GpsFileWriter() {
            start = end = System.currentTimeMillis();
        }

        public void run() {
            while (true) {
                try {
                    long writeInterval = end - start;
                    log.info("current writeTotal:{},write interval:{}", writeTotal, writeInterval);
                    if (writeTotal >= GpsFilesProperties.recordMax || (writeInterval > GpsFilesProperties.createInterval * 1000)) {

                        if (bufferedWriter != null) {
                            bufferedWriter.flush();
                            bufferedWriter.close();
                            bufferedWriter = null;
                        }

                        if (fileWriter != null) {
                            fileWriter.close();
                            fileWriter = null;
                        }
                        start = end = System.currentTimeMillis();
                        writeTotal = 0;
                        uploadFile(gpsFile);
                    }

                    if (fileWriter == null && bufferedWriter == null) {
                        String fileName = DateTimeUtil.getCurrentTime(DateTimeUtil.FULL_DATETIME_FORMAT);
                        gpsFile = new File(GpsFilesProperties.dir + "/" + fileName);
                        if (!gpsFile.exists()) {
                            log.info("create new file:{}", fileName);
                            gpsFile.createNewFile();
                        }
                        fileWriter = new FileWriter(gpsFile);
                        bufferedWriter = new BufferedWriter(fileWriter);
                    }

                    List<Gps> data = gpsCache.getData();
                    log.info("get data from cache,size:{}", data.size());
                    if (data != null && data.size() > 0) {
                        for (Gps gps : data) {
                            String line = JSONObject.toJSONString(gps);
                            bufferedWriter.write(line + "\n");
                            writeTotal++;
                            end = System.currentTimeMillis();
                        }
                        log.info("success to write data size:{},cur writeTotal:{}", data.size(), writeTotal);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    private void uploadFile(File gpsFile) throws Exception {
        if (gpsFile == null) {
            return;
        }
        gpsFtpManager.connect();
        log.info("gpsFtpManager connected success...");
        boolean res = gpsFtpManager.upload(gpsFile, null, GpsFtpProperties.rootDir);
        if (res) {
            log.info("upload file:{} success", gpsFile.getName());
            File targetFile = new File(GpsFilesProperties.bakDir + "/" + gpsFile.getName());
            FileUtil.move(gpsFile, targetFile, true);
            log.info("bak file:{} ---> {}", gpsFile.getName(), targetFile.getAbsolutePath());
        } else {
            log.info("upload file:{} failed", gpsFile.getName());
        }
        gpsFtpManager.close();
        log.info("gpsFtpManager closed");
    }

    class CLearGpsFile extends Thread {
        public void run() {
            File[] gpsFiles = new File(GpsFilesProperties.dir).listFiles();
            log.info("app restart,remain {} file to upload", gpsFiles.length);
            for (File file : gpsFiles) {
                try {
                    if (file.length() > 0 && (System.currentTimeMillis() - file.lastModified()) > GpsFilesProperties.createInterval * 1000) {
                        uploadFile(file);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }

            while (true) {
                File[] files = new File(GpsFilesProperties.bakDir).listFiles();
                try {
                    for (File file : files) {
                        long lastModified = file.lastModified();
                        if ((System.currentTimeMillis() - lastModified) > GpsFilesProperties.bakKeepTime * 60 * 1000) {
                            file.delete();
                        }
                    }
                    TimeUnit.MINUTES.sleep(GpsFilesProperties.bakClearInterval);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }
}
